package com.suixuan.support.log;

import java.lang.reflect.Method;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.lang.ArrayUtils;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 
 * Nanjing Zhou Su co.,Ltd
 * 
 * @Title: LogFactoryControlThread.java
 * @Package: com.suixuan.log
 * @Description: 记录控制器中的日志
 * @Author: suixuan
 * @Date 2010-7-22 下午03:18:44
 * @Version V1.0
 * 
 */
public class LogFactoryControlThread implements Runnable {
	private static final int QUEUE_MAX_SIZE = 1024 * 10 * 4;

	/**
	 * 双端阻塞队列
	 */
	private static BlockingQueue<Object[]> objsQueue = new LinkedBlockingQueue<Object[]>(QUEUE_MAX_SIZE);

	private static LogFactoryControlThread logFactoryControlThread;

	private static ExecutorService executor = Executors.newScheduledThreadPool(1);

	private LogFactoryControlThread() {
		super();
		// 启动线程
		executor.execute(this);
	}

	public static LogFactoryControlThread getInstance() {
		if (null == logFactoryControlThread) {
			logFactoryControlThread = new LogFactoryControlThread();
		}

		return logFactoryControlThread;
	}

	public void put(Object[] objs) {
		if (QUEUE_MAX_SIZE > objsQueue.size()) {
			try {
				objsQueue.put(objs);
			} catch (InterruptedException e) {
				// LogFactory.logRecord(LogConstant.ERROR, e.toString(), e);
			}
		}
	}

	@Override
	public void run() {
		Object[] objs = null;
		while (true) {
			try {
				objs = objsQueue.take();
			} catch (InterruptedException e) {
				// LogFactory.logRecord(LogConstant.ERROR, e.toString(), e);
				objs = null;
			}
			if (null != objs) {
				this.recordLog(objs);
			}
		}
	}

	/**
	 * 获取匹配的方法
	 * 
	 * @param objs
	 *            objs[0] 请求地址,objs[1] 控制器
	 * @return 匹配的方法
	 */
	private Method findMethod(Object[] objs) {
		Method[] methods = objs[1].getClass().getDeclaredMethods();
		RequestMapping requestMapping = null;
		for (Method method : methods) {
			requestMapping = method.getAnnotation(RequestMapping.class);
			if (null != requestMapping && (objs[2] + requestMapping.value()[0]).equals(objs[0])) {

				return method;
			}
		}

		return null;
	}

	/**
	 * 获取参数类型
	 * 
	 * @param method
	 *            {@link Method}
	 * @return 参数Class数组
	 */
	private Class<?>[] findParameterTypes(Method method) {
		if (null == method) {
			return null;
		}
		return method.getParameterTypes();
	}

	private void recordLog(Object[] objs) {
		Method method = this.findMethod(objs);
		Class<?>[] classes = this.findParameterTypes(method);
		if (!ArrayUtils.isEmpty(classes)) {
			recordLog(objs[1].getClass().getName(), method.getName(), classes);
		} else {
			recordLog(objs[1].getClass().getName(), method.getName(), null);
		}
	}

	private static String splitKey = ", ";

	/**
	 * 记录日志
	 * 
	 * @param clazz
	 *            调用类Class
	 * @param methodName
	 *            调用方法名
	 * @param classes
	 *            调用参数Class
	 */
	private void recordLog(String className, String methodName, Class<?>[] classes) {
		StringBuffer logsBuff = new StringBuffer();
		logsBuff.append("Class name is ").append(className).append(" ");
		logsBuff.append("Method name is ").append(methodName).append(" ");
		logsBuff.append("Parameter is [");

		for (int i = 0; null == classes ? false : i < classes.length; i++) {
			logsBuff.append('{').append(null == classes[i] ? null : classes[i].getName()).append(splitKey).append('}');

			if (i < classes.length - 1) {
				logsBuff.append(splitKey);
			}
		}
		logsBuff.append(']');
		// LogFactory.logRecord(LogConstant.INFO, logsBuff.toString());
	}

}
